// **************************************************************
// COPYRIGHT(c)2022, Xidian University
// All rights reserved.
//
// IP LIB INDEX :  
// IP Name      :      
// File name    :  
// Module name  :  
// Full name    :  
// Time         : 2022
// Author       : Wang-Zhenuyu 
// Email        : 2047593704@qq.com
// Data         : 
// Version      : V 2.0 
// 
// Abstract     :
// Called by    :  
// 
// Modification history
// -----------------------------------------------------------------
// 
// 
//
// *****************************************************************

//*************************
//TIMESCALE
//*************************
`timescale 1ns/1ps

//*************************
//INFORMATION
//*************************

//*************************
//DEFINE(s)
//*************************
//`define UDLY 1  //Unit delay, for non-blocking assignments in sequential logic

//*************************
//DEFINE MODULE PORT
//*************************
module pkt_analysis_m2(
    //输入
    input wire rst_n,
    input wire pkt_clk_i,
    input wire pkt_sop_i,
    input wire pkt_eop_i,
    input wire[255:0] pkt_data_i,
    //input wire analyser_en,
    input wire pbb_uca,
    input wire[23:0] pbb_i_sid,
    //输出
    output reg[8:0] layend,
    //output reg layend_en,
    output reg[0:1023] match_field,
    output wire analyser_is_working_o,
    output wire analyser_is_done_o
    //output reg[263:0] payload
    //output reg payload_en
);

//*************************
//DEFINE LOCAL PARAMETER
//*************************
//parameter(s)\
parameter IDLE = 3'b000;
parameter ETH   = 3'b001;
parameter ARP   = 3'b010;

parameter field_tab_item_00_i=8'h04;//MAC目的地址前16bit                     
parameter field_tab_item_01_i=8'h00;//MAC目的地址中16bit                     
parameter field_tab_item_02_i=8'h0c;//MAC目的地址后16bit                     
parameter field_tab_item_03_i=8'h08;//MAC源地址前16bit                     
parameter field_tab_item_04_i=8'h14;//MAC源地址中16bit                     
parameter field_tab_item_05_i=8'h10;//MAC源地址后16bit 
parameter field_tab_item_06_i=8'h03;//以太网帧类型 
//这里为了使用窗口过滤，对ARP编码成L3，不具有实际的意义
parameter field_tab_item_07_i=8'h09;//ARP_OP
parameter field_tab_item_08_i=8'h19;//发送方IP地址前16bit
parameter field_tab_item_09_i=8'h25;//发送方IP地址后16bit
parameter field_tab_item_10_i=8'h35;//接收方IP地址前16bit
parameter field_tab_item_11_i=8'h31;//接收方IP地址后16bit
parameter field_tab_item_12_i=8'h15;//发送方以太网地址前16bit
parameter field_tab_item_13_i=8'h11;//发送方以太网地址中16bit
parameter field_tab_item_14_i=8'h1d;//发送方以太网地址后16bit
parameter field_tab_item_15_i=8'h21;//接收方以太网地址前16bit
parameter field_tab_item_16_i=8'h2d;//接受方以太网地址中16bit
parameter field_tab_item_17_i=8'h29;//接收方以太网地址后16bit
//*************************
//INNER SIGNAL DECLARATION
//*************************
//REGS
reg[2:0] current_layer,next_layer;
reg[255:0] pkt_data_d1,pkt_data_d2;
reg[15:0] ether_type;
reg ether_type_en;
reg pkt_sop_d1;
reg pkt_eop_d1,pkt_eop_d2,pkt_eop_d3;
reg[1:0] eth_word_cnt,arp_word_cnt;

//WIRES
wire[15:0] window_reg_00_wdata_o,window_reg_01_wdata_o,window_reg_02_wdata_o,window_reg_03_wdata_o,window_reg_04_wdata_o,window_reg_05_wdata_o;
wire[15:0] window_reg_06_wdata_o,window_reg_07_wdata_o,window_reg_08_wdata_o,window_reg_09_wdata_o,window_reg_10_wdata_o,window_reg_11_wdata_o;
wire[15:0] window_reg_12_wdata_o,window_reg_13_wdata_o,window_reg_14_wdata_o,window_reg_15_wdata_o,window_reg_16_wdata_o,window_reg_17_wdata_o;

//***********************
//MAIN CODE
//***********************
wire[255:0] pkt_data_for_eth;
wire[255:0] pkt_data_for_arp;


always@(posedge pkt_clk_i or negedge rst_n)
begin
    if(!rst_n)
    begin 
        pkt_data_d1 <= 0;
        pkt_data_d2 <= 0;
    end
    else
    begin
        pkt_data_d1 <= pkt_data_i;
        pkt_data_d2 <= pkt_data_d1;
    end
end
always@(posedge pkt_clk_i or negedge rst_n)
begin
    if(!rst_n)
    begin
        pkt_sop_d1 <= 1'b0;
    end
    else
    begin
        pkt_sop_d1 <= pkt_sop_i;
    end
end
always@(posedge pkt_clk_i or negedge rst_n)
begin
    if(!rst_n)
    begin
        pkt_eop_d1 <= 1'b0;
        pkt_eop_d2 <= 1'b0;
        pkt_eop_d3 <= 1'b0;
    //    pkt_eop_d4 <= 1'b0;
    end
    else
    begin
        pkt_eop_d1 <= pkt_eop_i;
        pkt_eop_d2 <= pkt_eop_d1;
        pkt_eop_d3 <= pkt_eop_d2;
    //    pkt_eop_d4 <= pkt_eop_d3;
    end
end

assign pkt_data_for_eth = pkt_data_d1[255:0];
assign pkt_data_for_arp = {pkt_data_d2[143:0],pkt_data_d1[255:144]};

wire[255:0] pkt_data_in_layer;
assign pkt_data_in_layer = (current_layer==3'b010)?pkt_data_for_arp:
                           (current_layer==3'b001)?pkt_data_for_eth:
                           256'b0;

always@(posedge pkt_clk_i or negedge rst_n)
begin
    if(!rst_n)
    begin
        layend    <= 9'b0;
        //layend_en <= 1'b0;
    end
    else
    begin
        layend    <= 9'b0;
        //layend_en <= 1'b0;
    end
end

always@(posedge pkt_clk_i or negedge rst_n)
begin
    if(!rst_n)
    begin
        current_layer <= IDLE;
    end
    else
    begin
        current_layer <= next_layer;
    end
end

always@(*)
begin
    case(current_layer)
      IDLE:
      begin
          if(pkt_sop_i)
          begin
              next_layer = ETH;
          end
          else
          begin
              next_layer = IDLE;
          end
      end
      ETH:
      begin
          if( pkt_eop_d3 || eth_word_cnt > 2'd2)
          begin
              next_layer = IDLE;
          end
          else if (pkt_data_for_eth[159:144]==16'h0806 && eth_word_cnt==2'd0)
          begin
              next_layer = ARP;
          end
          else
          begin
              next_layer = ETH;
          end
      end
      ARP:
      begin
          if(pkt_eop_d3 || arp_word_cnt > 2'd2)
          begin
              next_layer = IDLE;
          end
          else
          begin
            next_layer = ARP;
          end
      end
      default:
      begin
          next_layer = IDLE;
      end
    endcase
end
reg is_arp;
reg pkt_analyser_is_working_d1;
reg pkt_analyser_is_working_d2;

always@(posedge pkt_clk_i or negedge rst_n)
begin
    if(!rst_n)
    begin
        is_arp <= 1'b0;
        ether_type <= 16'b0;
        ether_type_en <= 16'b0;
        eth_word_cnt <= 2'b0;
        arp_word_cnt <= 2'b0;
    end
    else
    begin
        case(current_layer)
          IDLE:
          begin
              is_arp <= 1'b0;
              ether_type <= 16'b0;
              ether_type_en <= 16'b0;
              eth_word_cnt <= 2'd0;
              arp_word_cnt <= 2'd0;
          end
          ETH:
          begin
              if(eth_word_cnt==2'd0 && pkt_data_for_eth[159:144]==16'h0806)
                is_arp <= 1'b1;
              else
                is_arp <= is_arp;

              if(eth_word_cnt==2'd0 /*&& pkt_data_for_eth[159:144]==16'h0806*/)
              begin
                  ether_type <= pkt_data_for_eth[159:144];
                  ether_type_en <= 1'b1;
                  if(pkt_data_for_eth[159:144]==16'h0806)
                    eth_word_cnt <= eth_word_cnt;
                  else
                    eth_word_cnt <= eth_word_cnt +2'd1;
              end
              else
              begin
                  ether_type <= ether_type;
                  ether_type_en <= ether_type_en;
                  eth_word_cnt <= eth_word_cnt + 2'd1;
              end
          end
          ARP:
          begin
              is_arp <= is_arp;
              ether_type <= ether_type;
              ether_type_en <= ether_type_en;
              arp_word_cnt <= arp_word_cnt + 2'b1;
          end
          default:
          begin
              is_arp <= 1'b0;
              ether_type <= 16'b0;
              ether_type_en <= 16'b0;
              eth_word_cnt <= 2'd0;
              arp_word_cnt <= 2'd0;
          end
        endcase
    end
end

wire pkt_analyser_is_working;
assign pkt_analyser_is_working =  ((current_layer==3'b001)||(current_layer==3'b010));
assign analyser_is_working_o   = pkt_analyser_is_working;

always@(posedge pkt_clk_i or negedge rst_n)
begin
    if(!rst_n)
    begin
        pkt_analyser_is_working_d1 <= 1'b0;
        pkt_analyser_is_working_d2 <= 1'b0;
    end
    else
    begin
        pkt_analyser_is_working_d1 <= pkt_analyser_is_working;
        pkt_analyser_is_working_d2 <= pkt_analyser_is_working_d1;
    end
end

assign analyser_is_done_o = (!pkt_analyser_is_working_d1) & pkt_analyser_is_working_d2;

always@(posedge pkt_clk_i or negedge rst_n)
begin
    if(!rst_n)
    begin
        match_field <= 1024'b0;
    end
    else if(is_arp)
    begin
        match_field <= {window_reg_00_wdata_o,window_reg_01_wdata_o,window_reg_02_wdata_o,window_reg_03_wdata_o,window_reg_04_wdata_o,window_reg_05_wdata_o,
        window_reg_06_wdata_o,window_reg_07_wdata_o,window_reg_08_wdata_o,window_reg_09_wdata_o,window_reg_10_wdata_o,window_reg_11_wdata_o,
        window_reg_12_wdata_o,window_reg_13_wdata_o,window_reg_14_wdata_o,window_reg_15_wdata_o,window_reg_16_wdata_o,window_reg_17_wdata_o,7'b0,pbb_uca,pbb_i_sid,704'b0};
    end
    else
    begin
        match_field <= {window_reg_00_wdata_o,window_reg_01_wdata_o,window_reg_02_wdata_o,window_reg_03_wdata_o,window_reg_04_wdata_o,window_reg_05_wdata_o,
        window_reg_06_wdata_o,176'b0,7'b0,pbb_uca,pbb_i_sid,704'b0};
    end
end
/*
always@(posedge pkt_clk_i or negedge rst_n)
begin
    if(!rst_n)
    begin
        payload <= 264'b0;
        payload_en <= 1'b0;
    end
    else
    begin
        payload <= 264'b0;
        payload_en <= 1'b0;
    end
end
*/
window_filter window_filter_00(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_00_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_00_wdata_o)
    );
    window_filter window_filter_01(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_01_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_01_wdata_o)
    );
    window_filter window_filter_02(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_02_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_02_wdata_o)
    );
    window_filter window_filter_03(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_03_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_03_wdata_o)
    );
    window_filter window_filter_04(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_04_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_04_wdata_o)
    );
    window_filter window_filter_05(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_05_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_05_wdata_o)
    );
    window_filter window_filter_06(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_06_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_06_wdata_o)
    );
    window_filter window_filter_07(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_07_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_07_wdata_o)
    );
    window_filter window_filter_08(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_08_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_08_wdata_o)
    );
    window_filter window_filter_09(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_09_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_09_wdata_o)
    );
    window_filter window_filter_10(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_10_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_10_wdata_o)
    );
    window_filter window_filter_11(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_11_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_11_wdata_o)
    );
    window_filter window_filter_12(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_12_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_12_wdata_o)
    );
    window_filter window_filter_13(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_13_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_13_wdata_o)
    );
    window_filter window_filter_14(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_14_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_14_wdata_o)
    );
    window_filter window_filter_15(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_15_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_15_wdata_o)
    );
    window_filter window_filter_16(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_16_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_16_wdata_o)
    );
    window_filter window_filter_17(
    .rst_n               (rst_n),
    .pkt_clk_i           (pkt_clk_i),
    .pkt_data_i          (pkt_data_in_layer),
    .active_layer_i      (current_layer),
    .l2_word_cnt_i        (eth_word_cnt),
    .l3_dword_cnt_i        (arp_word_cnt),
    .l4_dword_cnt_i      (2'b0),
    .field_tab_item_i    (field_tab_item_17_i),
    .ether_type_i        (ether_type),
    .ether_type_en_i     (ether_type_en),
    .window_reg_wdata_o  (window_reg_17_wdata_o)
    );
   
   endmodule